#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <event.h>
#include <event2/event.h>
#include <event2/listener.h>

#include "error.h"
#include "config.h"
#include "threadpool.h"

#define EVENT_LISTEN_SIGNAL            1  /* libevent监听信号事件 */


// epoll demo https://www.cnblogs.com/cthon/p/9139384.html
// https://gitee.com/fortunely/linuxstudy/blob/master/advancedio/epoll/epoll_EPOLLONESHOT.c
// https://gitee.com/fortunely/linuxstudy/blob/master/advancedio/epoll/epoll.c

void print_local_ip_port()
{

}

/**
 * 控制连接监听回调
 * @param listener 连接监听器
 * @param fd 连接文件描述符
 * @param sa 对端ip地址信息
 * @param socklen sa结构对象大小
 * @param arg 用户传入参数
 */
void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *arg)
{
//    struct event_base *base = (struct event_base *)arg;
    struct sockaddr_in local, *peer;
    socklen_t len;

    if (getsockname(fd, (struct sockaddr *)&local, &len) < 0) {
        err_ret("getsockname error");
        return;
    }
    printf("Connected on local port %u, sending welcome message.\n", ntohs(local.sin_port));

    peer = (struct sockaddr_in *)sa;
    printf("Connected to client %s:%u\n", inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));

    Task *task = task_new();
    task_setConnfd(task, fd);

    ThreadPool *pool = threadPool_getInstance();
    if (threadpool_dispatchTask(pool, task) < 0) {
        fprintf(stderr, "threadpool_dispatchTask error\n");
        return;
    }
}

/**
 * 控制连接监听错误处理回调
 * @param listener 连接监听器
 * @param ctx 用户传入参数
 */
static void listen_error_cb(struct evconnlistener *listener, void *ctx)
{
    struct event_base *base = evconnlistener_get_base(listener);
    int err;
    if ((err  = EVUTIL_SOCKET_ERROR()) != 0) { // 获取socket错误
        fprintf(stderr, "Got an error on the listner: %s. "
                        "Shutting down.\n", evutil_socket_error_to_string(err));
    }

    event_base_loopexit(base, NULL); /* 如果有激活事件，等激活事件回调运行完就退出事件循环；否则，立即退出 */
}

#ifdef EVENT_LISTEN_SIGNAL
/**
 * 信号处理回调函数
 * @param sig_no 信号
 * @param events 事件
 * @param user_data 用户传入数据
 */
void signal_cb(evutil_socket_t sig_no, short events, void *arg)
{
    struct event_base *base = (struct event_base *)arg;
    if (sig_no == SIGINT || sig_no == SIGTERM) {
        printf("Caught signal SIGINT or SIGTERM, will break loop\n");

        /* 退出event事件循环 */
        event_base_loopbreak(base);
    } else if (sig_no == SIGPIPE) {
        /* 忽略SIGPIPE信号 */
        printf("Caught signal SIGPIPE, ignore");
    }
}

#else
static struct event_base *g_base = NULL;

/**
 * 信号处理函数
 * @param sig_no 信号值
 */
static void sig_func(int sig_no)
{
    if (sig_no == SIGINT || sig_no == SIGTERM) {
        if (g_base) {
            printf(stderr, "SIGINT or SIGTERM");
            event_base_loopbreak(g_base);
        }
    }
}
#endif

#include "hashmap.h"
Boolean str_equal(let key1, let key2)
{
    if (!key1 || !key2) return False;
    string s1 = (string)key1;
    string s2 = (string)key2;

    return strcmp(s1, s2) == 0 ? True : False;
}

int main(int argc, char *argv[]) {
#ifndef EVENT_LISTEN_SIGNAL
    // 忽略SIGPIPE信号，防止服务器异常终止
    signal(SIGPIPE, SIG_IGN);
    // 调试用，中断时退出
    signal(SIGINT, sig_func);
    signal(SIGTERM, sig_func);
#endif

    unsigned int port;
    char *ip;
    printf("Hello, E-FTP Server is starting\n");

    /* 读取配置信息 */
    config_init();
    ip = config_getIP();
    port = cofig_getCtrlPort();

    /* 初始化IO管理线程 */
//    threadio_init();

    /* 初始化线程池 */
    threadpool_init(threadPool_getInstance(), config_getNumberOfThreadMax());

    /* 创建event_base 对象, 监听连接 */
    struct event_base *base;
    base = event_base_new();
    if (!base) {
        fprintf(stderr, "Could not initialize libevent!\n");
        return 1;
    }

#ifndef EVENT_LISTEN_SIGNAL
    g_base = base;
#endif

    /* 初始化服务器地址信息 */
    struct sockaddr_in servaddr;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    if (inet_pton(AF_INET, ip, &servaddr.sin_addr) < 0) {
        err_sys("inet_pton error on ip %s", ip);
    }
    servaddr.sin_port = htons(port);

    /* 创建连接监听器 */
    struct evconnlistener *listener;
    listener = evconnlistener_new_bind(base, listener_cb, base,
                                       LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1,
                                       (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (!listener) {
        fprintf(stderr, "Could not create a listener: %s!\n", evutil_socket_error_to_string(errno));
        exit(1);
    }
    evconnlistener_set_error_cb(listener, listen_error_cb); /* 设置连接监听器的错误回调 */

#ifdef EVENT_LISTEN_SIGNAL
    /* 创建信号监听器 */
    struct event *signal_event;
    signal_event = evsignal_new(base, SIGINT | SIGTERM | SIGPIPE, signal_cb, base); /* 创建信号处理器 */
    if (!signal_event || evsignal_add(signal_event, NULL) < 0) {
        fprintf(stderr, "Could not create or add a signal event!\n");
        exit(1);
    }
#endif

    /* 事件循环 */
    event_base_dispatch(base); /* <=> event_base_loop(base, 0) */

    /* 释放资源 */
    event_free(signal_event);
    evconnlistener_free(listener);
    event_base_free(base);

    printf("E-FTP Server closed\n");
    return 0;
}

